package remato.client.view.requirementstable;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import remato.client.controller.exceptions.RematoClientException;
import remato.client.model.AbstractPropertySpesification;
import remato.client.model.ClientModelItem;
import remato.client.model.Configuration;
import remato.client.model.RequirementWrapper;
import remato.client.model.facade.INodeChild;
import remato.client.model.facade.INodeParent;
import remato.client.model.facade.IRequirementTableProvider;
import remato.client.view.facade.IModelTableEditor;

/**
 * 
 * @author Petter L. H. Eide
 * @version $Id: TableContentProvider.java,v 1.2 2006-01-30 21:52:33 petterei Exp $
 */
public class TableContentProvider implements IStructuredContentProvider, IModelTableEditor<ClientModelItem> {

    private TableViewer currentViewer;
    
//    private List<AbstractPropertySpesification> typeSpesifications = new ArrayList<AbstractPropertySpesification>();

    private List<AbstractPropertySpesification> nodespesifications = new ArrayList<AbstractPropertySpesification>();

    private List<AbstractPropertySpesification> requirementspesifications = new ArrayList<AbstractPropertySpesification>();

    private List<INodeChild> rows = new ArrayList<INodeChild>();

    private List<TableColumn> oldColumns = new ArrayList<TableColumn>();
    
    /**
     * 
     */
    public TableContentProvider() {
        super();
    }

    /**
     * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
     */
    public Object[] getElements(@SuppressWarnings("unused") Object inputElement) {
        return rows.toArray();
    }

    /**
     * @see org.eclipse.jface.viewers.IContentProvider#dispose()
     */
    public void dispose() {
//        typeSpesifications = null;
        nodespesifications = null;
        requirementspesifications = null;
        rows = new ArrayList<INodeChild>() ;
        oldColumns.clear();
        currentViewer = null;
    }

    /**
     * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
     */
    public synchronized void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        
        if (viewer instanceof TableViewer ) {
            // set viewer
            if (viewer != this.currentViewer) {
                this.currentViewer = (TableViewer) viewer;
            }

            if (newInput instanceof IRequirementTableProvider) {

                IRequirementTableProvider type = (IRequirementTableProvider) newInput;
//                typeSpesifications = type.getUserDefinedTypes();

                rows = new ArrayList<INodeChild>();
                initRows(type, RequirementWrapper.class) ;

                clearTable();
                setupTable();
                
            } else {
                if ( oldInput != null) {
                    clearTable();
                    rows = new ArrayList<INodeChild>() ;
                }
            }

        } else {
            viewer = null;
            throw new RematoClientException("Not a known viewer: " + viewer.getClass().getSimpleName() + " (Need to be: " + TableViewer.class.getName() + ")");
        }
    }

    private void initRows(INodeParent<? extends INodeParent, ? extends INodeChild> parent, Class clazz) {
        for (INodeChild child : parent.getChildren()) {
            if (clazz.equals(child.getClass())) {
                rows.add(child);
            } else {
            	for ( Class iClazz : child.getClass().getInterfaces()) {
            		if (iClazz.equals(INodeParent.class)) {  
            			initRows((INodeParent)child, clazz);
            		}
            		throw new RematoClientException(getClass() + ": Not valid type in requirement hierarchy!");
            	}
            }
        }
    }
    
    private List<AbstractPropertySpesification> getSpesifications() {
        List<AbstractPropertySpesification> specs = new ArrayList<AbstractPropertySpesification>() ;

        // temporary
        Configuration conf = Configuration.getInstance();
        //changes:
        nodespesifications = new ArrayList<AbstractPropertySpesification>();
        nodespesifications.addAll(conf.getSortedNodeSpesifications());
        //changes:
        requirementspesifications = new ArrayList<AbstractPropertySpesification>();
        requirementspesifications.addAll(conf.getSortedRequirementSpesifications());

        specs.addAll(nodespesifications);
        specs.addAll(requirementspesifications);
//        specs.addAll(typeSpesifications);
        return specs;
    }
    
    private void setupTable() {
        List<AbstractPropertySpesification> specs = getSpesifications();
        int size = specs.size();
        Table table = currentViewer.getTable();
        table.setRedraw(true);
        // create new table layout:
        GridData gridData = new GridData(GridData.FILL_BOTH);
        gridData.grabExcessVerticalSpace = true;
        gridData.horizontalSpan = 3;
        table.setLayoutData(gridData);      
                        
        table.setLinesVisible(true);
        table.setHeaderVisible(true);

        TableColumn column;
        String[] columnNames = new String[size];
        CellEditor[] cellEditors = new CellEditor[size];

      
        int i = 0;
        for (AbstractPropertySpesification spec : specs) {
            
            column = new TableColumn(table, SWT.LEFT, i) ;
            column.setText(spec.getLabel());
            column.setWidth(100);



            oldColumns.add(column);

            columnNames[i] = spec.getLabel();
            CellEditor cellEditor = spec.getCellEditor(table);
//            cellEditor.getControl().setEnabled(!spec.isReadOnly());

            cellEditors[i] = cellEditor;

            i++;

                
                
            column.addSelectionListener(new SelectionAdapter() {
                 /**
                 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
                 */
                @Override
                public void widgetSelected(SelectionEvent e) {
                    TableColumnSorter sorter = (TableColumnSorter)currentViewer.getSorter();
                    sorter.setIndex(((TableColumn)e.getSource()).getParent().indexOf((TableColumn)e.getSource()));
                    currentViewer.setSorter(sorter);
                    currentViewer.refresh();
                }
            });
        }

        currentViewer.setColumnProperties(columnNames);
        currentViewer.setCellEditors(cellEditors);

        currentViewer.setCellModifier(new TableCellModifier(specs, columnNames, this));
        currentViewer.setLabelProvider(new TableLabelProvider(specs));

        currentViewer.setSorter( new TableColumnSorter(specs, columnNames) );

        table.redraw();
//        viewer.refresh();
//        table.re
    }
    
    private void clearTable() {

        Table table = currentViewer.getTable();
        
        for (TableColumn column : oldColumns) {
            column.dispose();
        }
        
        oldColumns.clear();

        if (! table.isDisposed()) {
//            table.removeAll();
//            table.clearAll();
        }

////        viewer.resetFilters();
        
//        viewer.refresh();
    	// => eclipse gives nullpointer

    }

    public void addElement(ClientModelItem element) {
    }

    public void removeElement(ClientModelItem element) {
    }

    public void updateElement(ClientModelItem element) {
        if (currentViewer != null) {
            currentViewer.refresh(element);
        }
    }

    @Deprecated
	public boolean insertAfter(@SuppressWarnings("unused") ClientModelItem insert, @SuppressWarnings("unused") ClientModelItem after) {
		return false;
	}

    
    
}
